package com.zg.datapush.engine;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.zg.common.core.dao.system.SysDatasource;
import com.zg.common.core.dao.system.SysDatasourceDao;
import com.zg.common.dds.DataSourceUtil;
import com.zg.datapush.constant.DataPushConstants;
import com.zg.common.core.dao.datapush.dao.DpFieldMappingDao;
import com.zg.common.core.dao.datapush.dao.DpInterfaceConfigDao;
import com.zg.common.core.dao.datapush.entity.DpFieldMapping;
import com.zg.common.core.dao.datapush.entity.DpInterfaceConfig;
import com.zg.common.core.dao.datapush.entity.DpPushTask;
import com.zg.datapush.exception.DataPushException;

import com.zg.datapush.handler.PushResult;
import com.zg.datapush.service.PushLogRecorder;
import com.zg.datapush.util.DataPushUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.http.*;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;



import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * REST接口推送引擎
 * @author zg
 */
@Component
@RequiredArgsConstructor
@Slf4j
public class RestPushEngine {

    private final DpInterfaceConfigDao interfaceConfigDao;
    private final DpFieldMappingDao fieldMappingDao;
    private final DataTransformEngine dataTransformEngine;
    private final ApplicationContext applicationContext;
    private final SysDatasourceDao sysDatasourceDao;
    private final PushLogRecorder pushLogRecorder;
    private final DataSourceUtil dataSourceUtil;
    private final JdbcTemplate jdbcTemplate;
    private final RestTemplate restTemplate = new RestTemplate();

    /**
     * 执行REST推送（单条推送模式）
     */
    public PushResult executeRestPush(DpPushTask task) {
        try {
            // 1. 获取源数据（支持增量推送）
            List<Map<String, Object>> sourceData = pushLogRecorder.executeWithLog(
                "获取源数据",
                this.getClass().getName(),
                "getSourceData",
                task,
                () -> getSourceData(task)
            );

            if (sourceData.isEmpty()) {
                PushResult result = PushResult.success("没有需要推送的数据", 0);
                result.setSuccessCount(0);
                result.setFailedCount(0);
                return result;
            }

            // 2. 获取接口配置
            DpInterfaceConfig interfaceConfig = pushLogRecorder.executeWithLog(
                "获取接口配置",
                this.getClass().getName(),
                "getInterfaceConfig",
                task.getId(),
                () -> getInterfaceConfig(task.getId())
            );

            if (interfaceConfig == null) {
                return PushResult.failure("接口配置不存在");
            }

            // 3. 获取字段映射配置
            List<DpFieldMapping> fieldMappings = pushLogRecorder.executeWithLog(
                "获取字段映射配置",
                this.getClass().getName(),
                "getFieldMappings",
                task.getId(),
                () -> getFieldMappings(task.getId())
            );

            // 4. 单条推送模式：逐条处理数据
            int successCount = 0;
            int failedCount = 0;
            StringBuilder errorMessages = new StringBuilder();

            for (int i = 0; i < sourceData.size(); i++) {
                Map<String, Object> singleRecord = sourceData.get(i);

                try {
                    // 转换单条数据
                    Map<String, Object> transformedRecord = pushLogRecorder.executeWithLog(
                        String.format("数据转换-第%d条", i + 1),
                        DataTransformEngine.class.getName(),
                        "transformSingleRecord",
                        singleRecord,
                        () -> dataTransformEngine.transformSingleRecord(singleRecord, fieldMappings)
                    );

                    // 推送单条数据
                    boolean pushSuccess = pushLogRecorder.executeWithLog(
                        String.format("推送数据-第%d条", i + 1),
                        this.getClass().getName(),
                        "pushSingleRecord",
                        transformedRecord,
                        () -> {
                            if (DataPushConstants.PUSH_TYPE_CUSTOM.equals(interfaceConfig.getPushType())) {
                                return executeSingleCustomPush(interfaceConfig, transformedRecord);
                            } else {
                                return executeSingleDefaultPush(interfaceConfig, transformedRecord);
                            }
                        }
                    );

                    if (pushSuccess) {
                        successCount++;
                    } else {
                        failedCount++;
                    }

                } catch (Exception e) {
                    failedCount++;
                    String errorMsg = String.format("第%d条数据推送失败: %s", i + 1, e.getMessage());
                    errorMessages.append(errorMsg).append("; ");
                    log.error(errorMsg, e);
                }
            }

            // 5. 构建推送结果
            PushResult result;
            if (failedCount == 0) {
                result = PushResult.success(String.format("推送完成，成功%d条", successCount));
            } else if (successCount == 0) {
                result = PushResult.failure(String.format("推送失败，失败%d条: %s", failedCount, errorMessages.toString()));
            } else {
                result = PushResult.success(String.format("推送完成，成功%d条，失败%d条: %s", successCount, failedCount, errorMessages.toString()));
            }

            result.setSuccessCount(successCount);
            result.setFailedCount(failedCount);
            return result;

        } catch (Exception e) {
            log.error("REST推送失败", e);
            return PushResult.failure("推送失败: " + e.getMessage());
        }
    }

    /**
     * 获取接口配置
     */
    private DpInterfaceConfig getInterfaceConfig(Long taskId) {
        return interfaceConfigDao.getOne(
            new LambdaQueryWrapper<DpInterfaceConfig>()
                .eq(DpInterfaceConfig::getTaskId, taskId)
        );
    }

    /**
     * 获取字段映射配置
     */
    private List<DpFieldMapping> getFieldMappings(Long taskId) {
        return fieldMappingDao.list(
            new LambdaQueryWrapper<DpFieldMapping>()
                .eq(DpFieldMapping::getTaskId, taskId)
                .orderByAsc(DpFieldMapping::getSortOrder)
        );
    }

    /**
     * 执行单条默认推送
     */
    private boolean executeSingleDefaultPush(DpInterfaceConfig config, Map<String, Object> data) {
        try {
            // 构建请求头
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.parseMediaType(DataPushConstants.MEDIA_TYPE_JSON));

            if (StrUtil.isNotBlank(config.getHeaders())) {
                @SuppressWarnings("unchecked")
                Map<String, String> headerMap = JSONUtil.toBean(config.getHeaders(), HashMap.class);
                headerMap.forEach(headers::set);
            }

            // 构建请求体（单条数据）
            String requestBody = buildSingleRequestBody(config.getRequestTemplate(), data);

            // 发送请求
            HttpEntity<String> entity = new HttpEntity<>(requestBody, headers);
            ResponseEntity<String> response = restTemplate.exchange(
                config.getUrl(),
                HttpMethod.valueOf(config.getHttpMethod().toUpperCase()),
                entity,
                String.class
            );

            return response.getStatusCode().is2xxSuccessful();

        } catch (Exception e) {
            log.error("单条默认推送执行失败", e);
            throw new RuntimeException("推送失败: " + e.getMessage(), e);
        }
    }

    /**
     * 执行单条自定义推送
     */
    private boolean executeSingleCustomPush(DpInterfaceConfig config, Map<String, Object> data) {
        try {
            // 通过反射获取自定义处理类
            Class<?> handlerClass = Class.forName(config.getHandlerClass());
            Object handler = applicationContext.getBean(handlerClass);

            // 调用指定方法（修改为单条数据）
            Method method = handlerClass.getMethod(config.getHandlerMethod(), Map.class, Map.class);

            PushResult result = (PushResult) method.invoke(handler, config, data);
            return result.isSuccess();

        } catch (Exception e) {
            log.error("单条自定义推送执行失败", e);
            throw new RuntimeException("自定义推送执行失败: " + e.getMessage(), e);
        }
    }

    /**
     * 执行默认推送（批量模式，保留兼容性）
     */
    private PushResult executeDefaultPush(DpInterfaceConfig config, List<Map<String, Object>> data) {
        try {
            // 构建请求头
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.parseMediaType(DataPushConstants.MEDIA_TYPE_JSON));

            if (StrUtil.isNotBlank(config.getHeaders())) {
                @SuppressWarnings("unchecked")
                Map<String, String> headerMap = JSONUtil.toBean(config.getHeaders(), HashMap.class);
                headerMap.forEach(headers::set);
            }

            // 构建请求体
            String requestBody = JSONUtil.toJsonStr(data);

            // 发送请求
            HttpEntity<String> entity = new HttpEntity<>(requestBody, headers);
            ResponseEntity<String> response = restTemplate.exchange(
                config.getUrl(),
                HttpMethod.valueOf(config.getHttpMethod().toUpperCase()),
                entity,
                String.class
            );

            if (response.getStatusCode().is2xxSuccessful()) {
                PushResult result = PushResult.success("推送成功", response.getBody());
                result.setSuccessCount(data.size());
                result.setFailedCount(0);
                return result;
            } else {
                PushResult result = PushResult.failure("推送失败，状态码: " + response.getStatusCode() +
                                                      ", 响应: " + response.getBody());
                result.setSuccessCount(0);
                result.setFailedCount(data.size());
                return result;
            }

        } catch (Exception e) {
            log.error("默认推送执行失败", e);
            PushResult result = PushResult.failure("推送失败: " + e.getMessage());
            result.setSuccessCount(0);
            result.setFailedCount(data.size());
            return result;
        }
    }

    /**
     * 执行自定义推送
     */
    private PushResult executeCustomPush(DpInterfaceConfig config, List<Map<String, Object>> data) {
        try {
            // 通过反射获取自定义处理类
            Class<?> handlerClass = Class.forName(config.getHandlerClass());
            Object handler = applicationContext.getBean(handlerClass);

            // 调用指定方法
            Method method = handlerClass.getMethod(config.getHandlerMethod(), List.class, Map.class);

            return (PushResult) method.invoke(handler, data);

        } catch (Exception e) {
            log.error("自定义推送执行失败", e);
            return PushResult.failure("自定义推送执行失败: " + e.getMessage());
        }
    }

    /**
     * 构建单条数据请求体
     * 支持模板格式：{ "id":"$ID", "instCode":"$INST_CODE", "flowCode":"$FLOW_CODE", "flowName":"$FLOW_NAME", "tJsl":"$T_JSL" }
     * 只支持 $字段名 格式，其他格式均为非法
     */
    private String buildSingleRequestBody(String template, Map<String, Object> data) {
        if (StrUtil.isBlank(template)) {
            // 如果没有模板，直接返回数据的JSON格式
            return JSONUtil.toJsonStr(data);
        }

        try {
            String result = template;

            // 使用正则表达式找到模板中所有的占位符
            Pattern pattern = Pattern.compile("\\$([A-Za-z_][A-Za-z0-9_]*)");
            Matcher matcher = pattern.matcher(template);

            // 收集所有需要替换的占位符
            Set<String> placeholders = new HashSet<>();
            while (matcher.find()) {
                placeholders.add(matcher.group(1)); // 获取字段名（不包含$）
            }

            // 替换所有占位符
            for (String fieldName : placeholders) {
                String placeholder = "$" + fieldName;

                // 获取对应的值，如果data中没有该字段，则使用空字符串
                Object value = data.get(fieldName);
                String valueStr;
                if (value == null) {
                    valueStr = "";
                } else if (value instanceof String) {
                    valueStr = (String) value;
                } else {
                    valueStr = String.valueOf(value);
                }

                // 替换占位符
                result = result.replace(placeholder, valueStr);
            }

            // 验证生成的JSON是否有效
            try {
                JSONUtil.parseObj(result);
                return result;
            } catch (Exception e) {
                log.warn("生成的JSON格式无效，返回原始数据: {}", result);
                return JSONUtil.toJsonStr(data);
            }

        } catch (Exception e) {
            log.error("构建请求体失败，使用原始数据", e);
            return JSONUtil.toJsonStr(data);
        }
    }

    /**
     * 获取源数据（支持增量推送）
     */
    private List<Map<String, Object>> getSourceData(DpPushTask task) {
        // 验证表名安全性
        if (!DataPushUtil.isValidTableName(task.getSourceTableName())) {
            throw new DataPushException(DataPushException.ErrorCodes.VALIDATION_ERROR,
                                      "无效的源表名: " + task.getSourceTableName());
        }

        // 验证源数据源是否存在
        SysDatasource sourceDs = sysDatasourceDao.getOne(
            new LambdaQueryWrapper<SysDatasource>()
                .eq(SysDatasource::getCode, task.getSourceDatasourceCode())
        );

        if (sourceDs == null) {
            throw new DataPushException(DataPushException.ErrorCodes.DATASOURCE_NOT_FOUND,
                                      "源数据源不存在: " + task.getSourceDatasourceCode());
        }

        // 使用DataSourceUtil切换到源数据源
        dataSourceUtil.change(task.getSourceDatasourceCode());

        try {
            String sql = buildSourceSql(task);
            return jdbcTemplate.queryForList(sql);
        } finally {
            // 清理数据源切换
            dataSourceUtil.clear();
        }
    }

    /**
     * 构建源数据查询SQL（支持增量推送）
     */
    private String buildSourceSql(DpPushTask task) {
        StringBuilder sql = new StringBuilder();
        sql.append("SELECT * FROM ").append(task.getSourceTableName());

        // 增量推送：添加时间条件
        if (DataPushConstants.PUSH_MODE_INCREMENT.equals(task.getPushMode()) &&
            StrUtil.isNotBlank(task.getIncrementField()) &&
            task.getLastPushTime() != null) {

            // 验证增量字段名安全性
            if (!DataPushUtil.isValidFieldName(task.getIncrementField())) {
                throw new DataPushException(DataPushException.ErrorCodes.VALIDATION_ERROR,
                                          "无效的增量字段名: " + task.getIncrementField());
            }

            // 使用Oracle的日期格式
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String formattedDate = dateFormat.format(task.getLastPushTime());

            sql.append(" WHERE ").append(task.getIncrementField())
               .append(" > TO_DATE('").append(formattedDate).append("', 'YYYY-MM-DD HH24:MI:SS')");
        }

        sql.append(" ORDER BY ");
        if (StrUtil.isNotBlank(task.getIncrementField())) {
            sql.append(task.getIncrementField());
        } else {
            sql.append("1"); // 默认排序
        }

        return sql.toString();
    }


}
